﻿//c:\download\ /scanoncee /cat Glossary /imgpath c:\wiki_import\images /artpath c:\wiki_import\articles /dbserver wikirs /db wikidb /dblogin root /dbpassword mysql /tableprefix meridianbeta_
//\\wikirs\articles_in\ /cat Glossary /imgpath c:\wiki_import\images /artpath c:\wiki_import\articles

using System;
using System.Data;
using System.Collections;
using MySql.Data.MySqlClient;

class AutoLinker
{
	public class Page
	{
		public Int32 pageId;
		public string pageTitle;
		public Int32 pageLatest;
		public Int32 pageNamespace;
	}

	// Conversion parameters.
	string DBServer = null;
	string DB = null;
	string DBLogin = null;
	string DBPassword = null;
	string TablePrefix = null;

	public ArrayList BreakOutParms(string Text)
	{
		ArrayList WorkingSectionList;
		bool inQuote;
		string WorkingText;

		Text = Text + " ";
		// Make sure we break at end
		WorkingText = "";
		inQuote = false;
		WorkingSectionList = new ArrayList();

		// Iterate through and break based on whitespaces, sans quoted things.
		foreach ( char ch in Text) {
			// Toggle for quotes.
			if ((ch == '\"'))
			{
				inQuote = !inQuote;
			}
			else
			{
				// In a quote - just copy chars over to the result.
				if ((inQuote))
				{
					WorkingText = WorkingText + ch;
				}
				// Break on a whitespace.
				else
				{
					if ((char.IsWhiteSpace(ch)))
					{
						WorkingSectionList.Add(WorkingText.Trim());
						WorkingText = "";
					}
					else
					{
						WorkingText = WorkingText + ch;
					}

				}

			}
		}
		return WorkingSectionList;

		// Return our split text.
	}

	public void MainCleanupProcess()
	{
		string connStr;
		MySqlConnection conn;

		// Make sure we've got enough data to connect to the DB.
		if ((DBServer == null) | (DB == null) | (DBLogin == null) | (DBPassword == null) | (TablePrefix == null))
		{
			conn = null;
		}
		else
		{
			// Log into MySQL.
			System.Console.WriteLine("Logging into MySQL (db=" + DB + ") as " + DBLogin);
			connStr = string.Format("server={0};user id={1}; password={2}; database={3}; pooling=false", DBServer, DBLogin, DBPassword, DB);

			conn = new MySqlConnection(connStr);
			conn.Open();
			conn.ChangeDatabase(DB);
			//System.Console.WriteLine("Here!  z22aa")
		}

		// Do our deed!
		System.Console.WriteLine("--------------------------------------------");
		System.Console.WriteLine("Scan time: " + System.DateTime.Now.ToString());
		System.Console.WriteLine("--------------------------------------------");
		System.Console.WriteLine();
		PerformArticleCleanup(conn, TablePrefix);

		// Log out of MySQL.
		if (((conn != null)))
		{
			System.Console.WriteLine("Logging out of MySQL");
			conn.Close();
		}
	}

	public void PerformArticleCleanup(MySqlConnection conn, string TablePrefix)
	{
		MySqlDataReader reader;
		ArrayList pageList;

		// Get a list of articles.  We need to the full list for processing
		// each one individually next.
		System.Console.Write("Obtaining article list...");
		pageList = new ArrayList();
		reader = Query(conn, "select page_id,page_namespace,page_title,page_latest from " + GetTableName(TablePrefix, "page") + " where page_namespace=0" + " order by  CHAR_LENGTH(page_title) desc");

		while ((reader.Read())) {
			Page thisPage;

			thisPage = new Page();
			thisPage.pageId = reader.GetInt32(0);
			thisPage.pageNamespace = reader.GetInt32(1);
			thisPage.pageTitle = reader.GetString(2);
			thisPage.pageLatest = reader.GetInt32(3);

			pageList.Add(thisPage);
		}
		reader.Close();

		System.Console.WriteLine("Found " + pageList.Count.ToString() + " total articles");

		// Iterate over all user articles.
		System.Console.WriteLine("Looking for dynamically linked articles...");

		Int32 i;
		for (i = 0; i <= (pageList.Count - 1); i++) {
			Page thisPage;
			thisPage = (Page) pageList[i];

			ConditionallyDeleteOneArticle(conn, TablePrefix, pageList, thisPage);
		}
	}

	public void ConditionallyDeleteOneArticle(MySqlConnection conn, string TablePrefix, ArrayList pageList, Page thisPage)
	{
		MySqlDataReader reader;
		Int32 TextId;
		string articleText;

		// Find the TextID for the article contents.
		reader = Query(conn, "select rev_text_id from " + GetTableName(TablePrefix, "revision") + " where rev_id=" + thisPage.pageLatest.ToString());
		if ((!reader.Read()))
		{
			reader.Close();
			return;
		}
		TextId = reader.GetInt32(0);
		reader.Close();

		// Get the text of the page.
		reader = Query(conn, "select old_text from " + GetTableName(TablePrefix, "text") + " where old_id=" + TextId.ToString());
		if ((!reader.Read()))
		{
			reader.Close();
			return;
		}
		reader.Read();
		articleText = reader.GetString(0);
		reader.Close();

		// Ignore articles of length=0.  For some reason deleted pages
		// sometime come across this way.
		if ((articleText.Trim().Length == 0))
		{
			return;
		}

		// See if this article is set up for cleanup.
		bool shouldDelete;
		shouldDelete = (articleText.IndexOf("<!-- LinkSource=") > 0);

		if ((shouldDelete))
		{
			System.Console.WriteLine(thisPage.pageTitle);
			DeleteExistingArticle(conn, thisPage.pageId);
		}
	}

	public string GetEscapedArticleText(string ArticleText)
	{
		string buf = "";
		int i;
		char ch;

		// Look for special chars in the input.
		for (i = 0; i <= (ArticleText.Length - 1); i++) {
			ch = ArticleText[i];

			// Double up certain chars.
			if (ch == '\'')
			{
				buf = buf + ch;
			}
			buf = buf + ch;
		}

		// Set our normalized result.
		return buf.Trim();
	}

	public string RemoveNonAlphaNumeric(string ArticleText)
	{
		string buf = "";
		int i;
		char ch;

		// Look for special chars in the input.
		for (i = 0; i <= (ArticleText.Length - 1); i++) {
			ch = ArticleText[i];

			// Double up certain chars.
			if (char.IsLetterOrDigit(ch))
			{
				buf = buf + ch;
			}
			else
			{
				buf = buf + " ";
			}
		}

		// Set our normalized result.
		return buf.Trim();
	}

	public string GetTableName(string TablePrefix, string TableName)
	{
		return TablePrefix + TableName;
	}

	public MySqlDataReader Query(MySqlConnection conn, string QueryStr)
	{
		MySqlCommand cmd;

		cmd = conn.CreateCommand();
		cmd.CommandText = QueryStr;
		return cmd.ExecuteReader();
	}

	public int Exec(MySqlConnection conn, string SQL)
	{
		MySqlCommand cmd;

		cmd = conn.CreateCommand();
		cmd.CommandText = SQL;
		return cmd.ExecuteNonQuery();
	}

	public static string GetStringLeft(string val, int charCount)
	{
		if (val.Length > charCount)
			return val.Substring(0, charCount);
		else
			return val;
	}

	public static string GetStringRight(string val, int charCount)
	{
		if (val.Length > charCount)
			return val.Substring(val.Length - charCount, charCount);
		else
			return val;
	}

	private void DeleteExistingArticle(MySqlConnection conn, int PageID)
	{
		string SQL;
		MySqlDataReader reader;
		string work;

		// Remove any existing category records for this sucker.
		SQL = "delete from " + GetTableName(TablePrefix, "categorylinks") 
			+ " where cl_from = " +  PageID;
		Exec(conn, SQL);

		// Remove the search index entries for this dude.
		SQL = "delete from " + GetTableName(TablePrefix, "searchindex") 
			+ " where si_page = " + PageID;
		Exec(conn, SQL);

		// Remove the page links.
		SQL = "delete from " + GetTableName(TablePrefix, "pagelinks")
			+ " where pl_from = " +  PageID;
		Exec(conn, SQL);

		// Remove text related to the page.
		work = "";
		reader = Query(conn, 
					"select rev_text_id from " + GetTableName(TablePrefix, "revision") 
			      + " where rev_page='" + PageID + "'");

		while (reader.Read())
		{
			if (work != "") 
			{
				work = work + ",";
			}
			work += reader.GetInt32(0).ToString();
		}
		reader.Close();

		if (work != "")
		{
			SQL = "delete from " + GetTableName(TablePrefix, "text") 
				+ " where old_id in (" + work + ")";
			Exec(conn, SQL);
		}

		// Remove the revisions.
		SQL = "delete from " + GetTableName(TablePrefix, "revision") 
			+ " where rev_page = " + PageID;
		Exec(conn, SQL);

		// Finally, remove the page record for this dude.
		SQL = "delete from " + GetTableName(TablePrefix, "page") 
			+ " where page_id = " + PageID;
		Exec(conn, SQL);
	}

	public static void Main(string[] ArgList)
	{
		System.Console.WriteLine();

		System.Console.WriteLine("=======================================================================");
		System.Console.WriteLine("Linked Document Sweeper");
		System.Console.WriteLine("Version 1.0a");
		System.Console.WriteLine("=======================================================================");
		System.Console.WriteLine();

		bool showHelp;
		if (ArgList.Length == 0) 
		{
			showHelp = true;
		}
		else if ((ArgList.Length == 1) && (ArgList[0] == "/?"))
		{
			showHelp = true;
		}
		else
		{
			showHelp = false;
		}

		if (showHelp)
		{
			System.Console.WriteLine("Deletes any articles that are dynamic linked to a non-wiki source.");
			System.Console.WriteLine();
			System.Console.WriteLine("Usage:");
			System.Console.WriteLine("WikiLinkedDocCleanup");
			System.Console.WriteLine("  [/dbserver xxxx]     - Server that is hosting the wiki's MySQL database");
			System.Console.WriteLine("  [/db xxxx]           - Name of the wiki's database on the server");
			System.Console.WriteLine("  [/dblogin xxxx]      - Login name for the database");  
			System.Console.WriteLine("  [/dbpassword xxxx]   - Password for logging into the database");
			System.Console.WriteLine("  [/tableprefix xxxx]  - Prefix applied to all wiki tables");
			System.Console.WriteLine();
			System.Console.WriteLine("Example:");
			System.Console.WriteLine("/dbserver wikisvr /db wikidb /dblogin root /dbpassword rootpw /tableprefix wikibeta_");
		}
		else
		{
			try 
			{
				// Construct our linker instance.
				AutoLinker linker = new AutoLinker();

				// Parse the argument list.  Iterate over each parm.
				System.Console.WriteLine("[Debug]");
				string NextParm = null;
				foreach ( string Arg in ArgList) 
				{
					System.Console.WriteLine("Arg=" + Arg);

					// Look for any simple args.
					/*if ((Arg == "/scanonce"))
					{
						linker.ScanOnce = true;
					}*/

					// See if the value is second part of a tagged one.
					// The preceding parm has a  '/' prefix).
					if ((NextParm == "dbserver"))
					{
						linker.DBServer = Arg;
					}

					if ((NextParm == "db"))
					{
						linker.DB = Arg;
					}

					if ((NextParm == "dblogin"))
					{
						linker.DBLogin = Arg;
					}

					if ((NextParm == "dbpassword"))
					{
						linker.DBPassword = Arg;
					}

					if ((NextParm == "tableprefix"))
					{
						linker.TablePrefix = Arg;
					}

					NextParm = null;

					// look for prefixes and store what type for the next iteration.
					if (GetStringLeft(Arg, 1) == "/")
					{
						NextParm = GetStringRight(Arg, Arg.Length - 1);
					}
				}

				// Dump out our final config info for debugging purposes.
				System.Console.WriteLine("");
				System.Console.WriteLine("DBServer:    " + linker.DBServer);
				System.Console.WriteLine("DB:          " + linker.DB);
				System.Console.WriteLine("DBLogin:     " + linker.DBLogin);
				System.Console.WriteLine("DBPassword:  " + linker.DBPassword);
				System.Console.WriteLine("TablePrefix: " + linker.TablePrefix);
				System.Console.WriteLine();

				// Convert away!
				linker.MainCleanupProcess();
			}
			catch (Exception ex) 
			{
				System.Console.WriteLine();
				System.Console.WriteLine("Error!");
				System.Console.WriteLine(ex.Message);
				System.Console.WriteLine();
				System.Console.WriteLine(ex.StackTrace);
			}
		}
	}
}
